#ifndef CUSTOM_RC_COMMON_INCLUDED
#define CUSTOM_RC_COMMON_INCLUDED

#include "../Common.hlsl"

#define CASCADE_LEVEL_MAX 12
uniform float4 Cascade_ProbeNum_TexSize[CASCADE_LEVEL_MAX];       // x:ProbeNum_x     y:ProbeNum_y    z:TexSize_x     w:TexSize_y
uniform float4 Cascade_ProbeSize_AngleSize[CASCADE_LEVEL_MAX];    // x:ProbeSize_x    y:ProbeSize_y   z:AngleSize_x   w:AngleSize_y

/* 
AngleSize 4x4
12 13 14 15
 8  9 10 11
 4  5  6  7
 0  1  2  3
*/
struct ProbeInfo {
    int2    AngleSize;          // Angle sampling resolution in one probe
    float2  TexUV;              // Current Fragment Thread Texture UV
    int2    TexPix;             // Current Fragment Thread Texture Pix
    int2    TexSize;            // Output Texture Size
    int2    Probe;              // Probe Coordinate Address Probe(1, 2) x轴第二个Probe，y轴第三个Probe
    float2  ProbeLength;        // Probe对应的屏幕像素长度，用于计算当前Probe在屏幕中的位置，进行RayMarching
    float2  AngleLocalPix;      // 当前UV对应的AngleLocal位置，也就是上图的0 ~ 15
};

ProbeInfo GetProbeInfo(in int CascadeLevel, in float2 TexUV) {
    ProbeInfo Result;
    Result.AngleSize        = int2(Cascade_ProbeSize_AngleSize[CascadeLevel].zw);
    Result.TexUV            = TexUV;
    Result.TexPix           = int2(floor(Result.TexUV * Cascade_ProbeNum_TexSize[CascadeLevel].zw));
    Result.Probe            = int2(floor(Result.TexPix / Result.AngleSize));
    Result.AngleLocalPix    = Result.TexPix - Result.Probe * Result.AngleSize;
    Result.ProbeLength      = Cascade_ProbeSize_AngleSize[CascadeLevel].xy;
    Result.TexSize          = int2(Cascade_ProbeNum_TexSize[CascadeLevel].zw);
    
    return Result;
}

// Marching Parameters
#define MAX_MARCHING_STEP 32
// #define MARCHING_THREASHOLD 0.
#define MARCHING_THREASHOLD 1e-3
#define MAX_LENGTH 1e10

uniform Texture2D _Sdf_Texture;
SamplerState sampler_Sdf_Texture;

float4 RayMarching(in float2 InPos, in float2 InDir, in float InLength) {
    float t = 0.;

    int MarchingStep = 0;
    
    for (MarchingStep = 0; MarchingStep < MAX_MARCHING_STEP; MarchingStep++) {
        // Check Current t IsValid
        float2 RayPoint = InPos + t * InDir;
        // if (t > InLength || RayPoint.x < 0.0 || RayPoint.y < 0.0 || RayPoint.x > 1.0 || RayPoint.y > 1.0) break;
        if (t > InLength) break;

        // Marching
        // float4 SdfResult = Global_Sdf(RayPoint);
        // float4 SdfResult = _Sdf_Texture.Load(int3(RayPoint * _ScreenParams.y, 0));
        float4 SdfResult = _Sdf_Texture.Sample(sampler_Sdf_Texture, RayPoint * _ScreenParams.y / _ScreenParams.xy);
        if (SdfResult.w < MARCHING_THREASHOLD) { // Hit
            return float4(SdfResult.rgb, 0.0);
            // return float4(MarchingStep, MarchingStep, MarchingStep, MAX_MARCHING_STEP) / MAX_MARCHING_STEP;
            // break;
        }
        t += SdfResult.w;
    }

    // return float4(MarchingStep, MarchingStep, MarchingStep, MAX_MARCHING_STEP) / MAX_MARCHING_STEP;
    return float4(0.0, 0.0, 0.0, 1.0);
}

float4 BilinearLerp(float4 LD, float4 RD, float4 LU, float4 RU, float2 LerpCoef) {
    return lerp(lerp(LD, RD, LerpCoef.x), lerp(LU, RU, LerpCoef.x), LerpCoef.y);
}

// Sample a Cascade Texture
// Use ProbeIndex & AngleSize to Calculate Probe Pix Location
// Use AngleLocalIndex to Calculate Angle Pix Location
// Use SampleNum to MultiSample
float4 SampleCascade(Texture2D SampledTex, int2 ProbeIndex, int2 AngleSize, int AngleLocalIndex, int SampleNum) {
    float4 Result = float4(0, 0, 0, 0);

    int2 ProbePix = AngleSize * ProbeIndex;
    for (int SampleIndex = 0; SampleIndex < SampleNum; SampleIndex++) {
        int2 AngleLocalPix = int2((AngleLocalIndex + SampleIndex) % AngleSize.x, (AngleLocalIndex + SampleIndex) / AngleSize.x);
        Result += SampledTex.Load(int3(ProbePix + AngleLocalPix, 0)) / SampleNum;
    }

    return Result;
}

#endif